#include "driver_Mobvoi_includes.h"
#include "Mobvoi_external.h"
#include "app_Mobvoi_includes.h"
#include "driver_sdcard.h"
#include "ff.h"

int (*sd_rd_blk_sync_fptr)(int first_block, int block_num, uint8_t *dest) = NULL;

#define CLK_ENABLE (REG_SYSTEM_0x05 &= ~MSK_SYSTEM_0x05_SDIO_PWD)
#define CLK_DISABLE (REG_SYSTEM_0x05 |= MSK_SYSTEM_0x05_SDIO_PWD)

#define REG_READ(addr) (*((volatile uint32_t *)(addr)))
#define REG_WRITE(addr, _data) (*((volatile uint32_t *)(addr)) = (_data))

#define SD_DETECT

#ifdef SD_DETECT
#define SD_DETECT_GPIO 10
//static uint8_t SD_det_gpio_flag =0;
//static uint8_t SD_detect_pin =0;
#endif

//#define SD_DETECT_DEFAULT_GPIO   16

static SDCARD_S sdcard;
static uint8_t SDOnline = SD_CARD_OFFLINE;
//static uint8_t SD_detect_pin =0;

//static uint16_t cnt_online = 0;
//static uint16_t cnt_offline = 0;
//static uint8_t SD_Insert_flag = 0;
static uint16_t Sd_MMC_flag = 0;

// 0: inital state 1: read data ; 2: write data
static uint8_t SDIO_WR_flag = 0;
static uint8_t no_need_send_cmd12_flag = 1;
static uint32_t last_WR_addr = 0;

#define SD_DEBOUNCE_COUNT 120
#define SD_DETACH_COUNT 200

void sdio_gpio_config(void)
{
	uint32_t oldmask;

#ifdef CONFIG_M510_QFN68_DEMO
	//gpio_enable_second_function(GPIO_FUNCTION_SDIO);
	REG_GPIO_0x25 = 0x370;
	REG_GPIO_0x26 = 0x370;
	REG_GPIO_0x27 = 0x370;

// data 1 2 3 enable
#ifdef CONFIG_APP_SDCARD_4_LINE
	gpio_enable_second_function(GPIO_FUNCTION_SDIO_DATA1_3_ENABLE);
	REG_SYSTEM_0x1A = REG_SYSTEM_0x1A |(0x03 <<((34-32)*2) |(0x03 <<((35-32)*2))|(0x03 <<((36-32)*2));
#endif

	REG_SYSTEM_0x1A = REG_SYSTEM_0x1A |(0x03 <<10) |(0x03 <<12)|(0x03 << 14);
	REG_SYSTEM_0x18 = REG_SYSTEM_0x18 & (~((0x03<<16)|(0x03<<18)|(0x03<<20)));

	//sdio io position choose
	REG_SYSTEM_0x1A = (REG_SYSTEM_0x1A | MSK_SYSTEM_0x1A_SDIO_POS);
#endif

	oldmask = get_spr(SPR_VICMR(0));
    oldmask &= (~(1<<VIC_IDX_SDIO));
    set_spr(SPR_VICMR(0),oldmask);
}

void sdio_register_reset(void)
{
	uint32_t reg;

	/* Clear cmd rsp int bit */
	reg = REG_SDCARD_CMD_RSP_INT_SEL;

	REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL, reg);

	/* Clear tx/rx fifo */
	reg = SDCARD_FIFO_RX_FIFO_RST | SDCARD_FIFO_TX_FIFO_RST;
	REG_WRITE(REG_SDCARD_FIFO_THRESHOLD, reg);

	/* Disabe all sdio interrupt */
	reg = 0;
	REG_WRITE(REG_SDCARD_CMD_RSP_INT_MASK, reg);

	/* Config tx/rx fifo threshold */
	reg = ((SDCARD_RX_FIFO_THRD & SDCARD_FIFO_RX_FIFO_THRESHOLD_MASK)
		   << SDCARD_FIFO_RX_FIFO_THRESHOLD_POSI) |
		  ((SDCARD_TX_FIFO_THRD & SDCARD_FIFO_TX_FIFO_THRESHOLD_MASK)
		   << SDCARD_FIFO_TX_FIFO_THRESHOLD_POSI);
	REG_WRITE(REG_SDCARD_FIFO_THRESHOLD, reg);
}

/*
  0 -- 13M
  1 -- 6.5M
  2 -- 3.25M
*/

static void Mobvoi_sdcard_set_clk_div(uint8_t clkdiv)
{

	Delay(10);

	/*Config sdio clock*/
	uint32_t tmp = REG_SYSTEM_0x01;
	tmp &= ~MSK_SYSTEM_0x01_SDIO_DIV;
	tmp |= clkdiv << SFT_SYSTEM_0x01_SDIO_DIV;
	REG_SYSTEM_0x01 = tmp;
}

void sdio_set_low_clk(void)
{
	Mobvoi_sdcard_set_clk_div(CLK_3_25M);
}

void sdio_set_high_clk(void)
{
	Mobvoi_sdcard_set_clk_div(CLK_6_5M);
}

void sdio_clk_config(uint32_t enable)
{

	if (enable)
	{
		CLK_ENABLE;
	}
	else
	{
		CLK_DISABLE;
	}
}

void sdio_sendcmd_function(uint8_t cmd_index, uint32_t flag,
						   uint32_t timeout, VOID *arg)
{
	uint32_t reg;
	flag &= CMD_FLAG_MASK;

	reg = (uint32_t)arg;
	REG_WRITE(REG_SDCARD_CMD_SEND_AGUMENT, reg);

	reg = timeout;
	REG_WRITE(REG_SDCARD_CMD_RSP_TIMER, reg);

	reg = ((((uint32_t)cmd_index) & SDCARD_CMD_SEND_CTRL_CMD_INDEX_MASK)
		   << SDCARD_CMD_SEND_CTRL_CMD_INDEX_POSI) |
		  ((flag & SDCARD_CMD_SEND_CTRL_CMD_FLAGS_MASK)
		   << SDCARD_CMD_SEND_CTRL_CMD_FLAGS_POSI) |
		  SDCARD_CMD_SEND_CTRL_CMD_START;
	REG_WRITE(REG_SDCARD_CMD_SEND_CTRL, reg);
}

SDIO_Error sdio_wait_cmd_response(uint32_t cmd)
{
	uint32_t reg;

	while (1)
	{
		reg = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);
		//wait until cmd response
		if (reg & (SDCARD_CMDRSP_NORSP_END_INT | SDCARD_CMDRSP_RSP_END_INT | SDCARD_CMDRSP_TIMEOUT_INT))
		{
			break;
		}
	}

	REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL, SD_CMD_RSP); //clear the int flag
	if ((reg & SDCARD_CMDRSP_TIMEOUT_INT) /*||(reg&SDCARD_CMDRSP_NORSP_END_INT)*/)
	{
		if ((cmd != 1))
		{
			SDCARD_WARN("sdcard cmd %d timeout,cmdresp_int_reg:0x%x\r\n", cmd, reg);
		}
		return SD_CMD_RSP_TIMEOUT;
	}
	if (reg & SDCARD_CMDRSP_CMD_CRC_FAIL)
	{

		if ((cmd != 41) && (cmd != 2) && (cmd != 9) && (cmd != 1))
		{
			SDCARD_WARN("sdcard cmd %d crcfail,cmdresp_int_reg:0x%x\r\n", cmd, reg);
			return SD_CMD_CRC_FAIL;
		}
	}
	return SD_OK;
}

void sdio_get_cmdresponse_argument(uint8_t num, uint32_t *resp)
{
	switch (num)
	{
	case 0:
		*resp = REG_READ(REG_SDCARD_CMD_RSP_AGUMENT0);
		break;
	case 1:
		*resp = REG_READ(REG_SDCARD_CMD_RSP_AGUMENT1);
		break;
	case 2:
		*resp = REG_READ(REG_SDCARD_CMD_RSP_AGUMENT2);
		break;
	case 3:
		*resp = REG_READ(REG_SDCARD_CMD_RSP_AGUMENT3);
		break;
	default:
		break;
	}
}

void driver_sdcard_recv_data_start(int timeout)
{
	REG_WRITE(REG_SDCARD_DATA_REC_TIMER, timeout);
#ifdef CONFIG_SDCARD_BUSWIDTH_4LINE
	REG_WRITE(REG_SDCARD_DATA_REC_CTRL, (0x1 | (1 << 2) | (512 << 4) | (1 << 17)));
#else
	REG_WRITE(REG_SDCARD_DATA_REC_CTRL, (0x1 | (512 << 4) | (1 << 17)));
#endif
}

int wait_Receive_Data(void)
{
	uint32_t ret = SD_ERR_LONG_TIME_NO_RESPONS, status = 0;

	while (1)
	{

		status = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);
		if (status & SDCARD_CMDRSP_DATA_REC_END_INT)
		{
			if (status & SDCARD_CMDRSP_DATA_CRC_FAIL)
			{
				os_printf("aaa\r\n");
				//ret = SD_DATA_CRC_FAIL;
				ret = SD_OK;
			}
			else
			{
				ret = SD_OK;
			}
			break;
		}
		else if (status & SDCARD_CMDRSP_DATA_CRC_FAIL)
		{
			ret = SD_DATA_CRC_FAIL;
			break;
		}
		else if (status & SDCARD_CMDRSP_DATA_TIME_OUT_INT)
		{
			ret = SD_DATA_TIMEOUT;
			break;
		}
	}
	REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL, SD_DATA_RSP); /*< clear the int flag */
	return ret;
}

void sdio_setup_data(uint32_t data_dir, uint32_t byte_len)
{
	uint32_t reg;
	if (data_dir == SD_DATA_DIR_RD)
	{
		reg = REG_READ(REG_SDCARD_FIFO_THRESHOLD);
		reg &= (3 << 21);
		reg |= 0x3ffff; // set fifo
		REG_WRITE(REG_SDCARD_FIFO_THRESHOLD, reg);

		reg = SDCARD_DATA_REC_CTRL_DATA_EN;
	}
	else
		reg = SDCARD_DATA_REC_CTRL_DATA_WR_DATA_EN;

	reg |= SDCARD_DATA_REC_CTRL_DATA_BYTE_SEL | ((byte_len & SDCARD_DATA_REC_CTRL_BLK_SIZE_MASK) << SDCARD_DATA_REC_CTRL_BLK_SIZE_POSI)
#ifdef CONFIG_SDCARD_BUSWIDTH_4LINE
		   | SDCARD_DATA_REC_CTRL_DATA_BUS
#endif
		;

	REG_WRITE(REG_SDCARD_DATA_REC_CTRL, reg);
}

void sdio_set_data_timeout(uint32_t timeout)
{
	REG_WRITE(REG_SDCARD_DATA_REC_TIMER, timeout);
}

SDIO_Error sdcard_wait_receive_data(uint8_t *receive_buf)
{
	uint32_t reg, i;
	while (1)
	{
		reg = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);
		if (reg & (SDCARD_CMDRSP_DATA_REC_END_INT | SDCARD_CMDRSP_DATA_CRC_FAIL | SDCARD_CMDRSP_DATA_TIME_OUT_INT))
		{
			break;
		}
	}

	REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL, SD_DATA_RSP); //clear the int flag
	if (reg & SDCARD_CMDRSP_DATA_TIME_OUT_INT)
	{
		return SD_DATA_TIMEOUT;
	}
	if (reg & SDCARD_CMDRSP_DATA_CRC_FAIL)
	{
		SDCARD_WARN("sdcard data crcfail,cmdresp_int_reg:0x%x\r\n", reg);
		return SD_DATA_CRC_FAIL;
	}

	for (i = 0; i < SD_DEFAULT_BLOCK_SIZE;)
	{
		/* wait fifo data valid */
		while (1)
		{
			//software  needn't handle dead-loop,hardware can garantee
			if (REG_READ(REG_SDCARD_FIFO_THRESHOLD) & SDCARD_FIFO_RXFIFO_RD_READY)
				break;
		}
		reg = REG_READ(REG_SDCARD_RD_DATA_ADDR);
		*(receive_buf + i++) = reg & 0xff;
		*(receive_buf + i++) = (reg >> 8) & 0xff;
		*(receive_buf + i++) = (reg >> 16) & 0xff;
		*(receive_buf + i++) = (reg >> 24) & 0xff;
	}

	return SD_OK;
}

void sd_detect_init(void)
{
#ifdef SD_DETECT
	gpio_config(SD_DETECT_GPIO, 3);
#endif
	os_printf("SD_detect_pin:%d\r\n", SD_DETECT_GPIO);
}

#if 0
static SDIO_Error sd_connect_scanning(void)
{
#ifdef SD_DETECT
    if (gpio_input(SD_DETECT_GPIO))
    {
        if (SD_CARD_ONLINE == SDOnline)
        {
//          cnt_online = 0;
            SDOnline = SD_CARD_OFFLINE;
            sdcard.init_flag = 1;
//          msg_put(MSG_SD_DETACH);
//          DEBUG_SDIO_DPRINTF("SD check pin still high level,card is pull off oe nor inserted \r\n");
            os_printf("no sdcard\r\n");
        }
        return SD_ERROR;
    }
    else
#endif
    {
//        if (cnt_online < SD_DEBOUNCE_COUNT)
//        {
//            cnt_online ++;
//            DEBUG_SDIO_DPRINTF("check card inserted CNT<5\r\n");
//        }
        if (SD_CARD_OFFLINE == SDOnline)
        {
            SDOnline = SD_CARD_ONLINE;
            os_printf("sdcard insert\r\n");
        }
        return SD_OK;
    }
}
#endif

uint8_t sd_is_attached(void)
{
#ifdef SD_DETECT
	return (SDOnline == SD_CARD_ONLINE);
#else
	return SD_CARD_ONLINE;
#endif
}

int sdcard_get_size(void)
{
	return sdcard.total_block;
}

static uint16_t NoneedInitflag = 0;

static void sdio_hw_init(void)
{
	uint32_t tmp;

	//select sdio clk source :XTAL
	tmp = REG_SYSTEM_0x00;
	tmp &= ~(MSK_SYSTEM_0x00_CORE_DIV | MSK_SYSTEM_0x00_CORE_SEL);
	tmp |= (1 << 7);
	REG_SYSTEM_0x00 = tmp;

	//clsoe mem sd
	REG_SYSTEM_0x21 &= (~MSK_SYSTEM_0x21_SDIO_MEM_SD);
	REG_SYSTEM_0x06 = 0xFFFFFFFF;

	/* config sdcard gpio */
	sdio_gpio_config();

	/* reset sdcard moudle register */
	sdio_register_reset();

	/* set sdcard low clk */
	sdio_set_low_clk();

	/* set sdcard  clk enable*/
	sdio_clk_config(1);

	/* detect sdcard*/
	sd_detect_init();
}

static void sdio_hw_uninit(void)
{
	sdio_clk_config(0);
}

static void sdio_send_cmd(SDIO_CMD_PTR sdio_cmd_ptr)
{
	sdio_sendcmd_function(sdio_cmd_ptr->index,
						  sdio_cmd_ptr->flags,
						  sdio_cmd_ptr->timeout,
						  (void *)sdio_cmd_ptr->arg);
}

static void sdio_sw_init(void)
{
	os_memset((void *)&sdcard, 0, sizeof(SDCARD_S));
}

/******************************************************************************/
/***************************** sdcard function ********************************/
/******************************************************************************/
/* GO_IDLE_STATE */
static SDIO_Error sdcard_cmd0_process(void)
{
	SDCARD_FATAL("send cmd0 \r\n");

	SDIO_CMD_S cmd;

	cmd.index = GO_IDLE_STATE;
	cmd.arg = 0;
	cmd.flags = SD_CMD_NORESP;
	cmd.timeout = DEF_LOW_SPEED_CMD_TIMEOUT; //DEF_CMD_TIME_OUT;
	sdio_send_cmd(&cmd);

	cmd.err = sdio_wait_cmd_response(cmd.index);
	return cmd.err;
}

static SDIO_Error sdcard_cmd1_process(void)
{
	SDIO_CMD_S cmd;
	uint32_t response, reg;

	cmd.index = 1;
	cmd.arg = 0x40ff8000;
	cmd.flags = SD_CMD_SHORT;
	cmd.timeout = 0x900; //DEF_CMD_TIME_OUT;
cmd1_loop:
	sdio_send_cmd(&cmd);
	cmd.err = sdio_wait_cmd_response(cmd.index);
	if (cmd.err == SD_OK)
	{
		sdio_get_cmdresponse_argument(0, &response);
		if (!(response & OCR_MSK_VOLTAGE_ALL))
			cmd.err = SD_ERR_CMD41_CNT;
		if (!(response & OCR_MSK_BUSY))
			goto cmd1_loop;
		if (response & OCR_MSK_HC)
			sdcard.Addr_shift_bit = 0;
		else
			sdcard.Addr_shift_bit = 9;
	}
	reg = REG_READ(REG_SDCARD_FIFO_THRESHOLD);
	reg |= 20;
	REG_WRITE(REG_SDCARD_FIFO_THRESHOLD, reg);

	return cmd.err;
}

static SDIO_Error sdcard_mmc_cmd8_process(void)
{
	int i;
	SDIO_CMD_S cmd;

	uint32_t tmp;
	uint8_t *tmpptr = (uint8_t *)jmalloc(512, M_ZERO);
	if (tmpptr == NULL)
		return 1;
	os_memset(tmpptr, 0, 512);

	cmd.index = SEND_IF_COND;
	cmd.arg = 0;
	cmd.flags = SD_CMD_SHORT;
	cmd.timeout = 0x90000; // DEF_CMD_TIME_OUT;
	sdio_send_cmd(&cmd);

	if (cmd.err != SD_OK)
		goto freebuf;
	REG_WRITE(REG_SDCARD_FIFO_THRESHOLD, (1 << 20)); // reset first
	REG_WRITE(REG_SDCARD_FIFO_THRESHOLD, 0x3ffff);	 // set fifo later
	driver_sdcard_recv_data_start(DEF_CMD_TIME_OUT);

	tmp = 0;
	cmd.err = wait_Receive_Data();
	if (cmd.err == SD_OK)
	{
		for (i = 0; i < 128; i++)
		{
			while (!(REG_READ(REG_SDCARD_FIFO_THRESHOLD) & (0x1 << 18)))
			{
				tmp++;
				if (tmp > 0x20)
					break;
			}

			*((uint32_t *)tmpptr + i) = REG_READ(REG_SDCARD_RD_DATA_ADDR);
		}
		sdcard.total_block = tmpptr[212] | (tmpptr[213] << 8) | (tmpptr[214] << 16) | (tmpptr[215] << 24);
	}

freebuf:
	jfree_s(tmpptr);
	return cmd.err;
}

static SDIO_Error sdcard_cmd8_process(void)
{
	SDIO_CMD_S cmd;
	uint8_t voltage_accpet, check_pattern;

	cmd.index = SEND_IF_COND;
	cmd.arg = 0x1AA;
	cmd.flags = SD_CMD_SHORT;
	cmd.timeout = DEF_LOW_SPEED_CMD_TIMEOUT; // DEF_CMD_TIME_OUT;

	sdio_send_cmd(&cmd);
	cmd.err = sdio_wait_cmd_response(cmd.index);

	if (cmd.err == SD_CMD_RSP_TIMEOUT)
	{
		SDCARD_WARN("cmd8 noresp, voltage mismatch or Ver1.X SD or not SD\r\n");
		return SD_CMD_RSP_TIMEOUT;
	}
	else if (cmd.err == SD_CMD_CRC_FAIL)
	{
		SDCARD_WARN("cmd8 cmdcrc err\r\n");
		return SD_CMD_CRC_FAIL;
	}

	SDCARD_PRT("found a Ver2.00 or later SDCard\r\n");

	// check Valid Response,
	// R7-[11:8]:voltage accepted, [7:0] echo-back of check pattern
	sdio_get_cmdresponse_argument(0, &cmd.resp[0]);

	check_pattern = cmd.resp[0] & 0xff;
	voltage_accpet = cmd.resp[0] >> 8 & 0xf;

	if (voltage_accpet == 0x1 && check_pattern == 0xaa)
	{
		SDCARD_PRT("support 2.7~3.6V\r\n");
		return SD_OK;
	}
	else
	{
		SDCARD_WARN("unsupport voltage\r\n");
		return SD_INVALID_VOLTRANGE;
	}
	return SD_OK;
}

/*Send host capacity support information(HCS) and  asks
  the card to send its OCR in the response on CMD line*/
static SDIO_Error sdcard_acmd41_process(uint32_t ocr)
{
	SDIO_CMD_S cmd;

	cmd.index = APP_CMD;
	cmd.arg = 0;
	cmd.flags = SD_CMD_SHORT;
	cmd.timeout = DEF_LOW_SPEED_CMD_TIMEOUT; // DEF_CMD_TIME_OUT;
	sdio_send_cmd(&cmd);
	cmd.err = sdio_wait_cmd_response(cmd.index);
	if (cmd.err != SD_OK)
	{
		SDCARD_WARN("send cmd55 err:%d\r\n", cmd.err);
		return cmd.err;
	}

	cmd.index = SD_APP_OP_COND;
	cmd.arg = ocr;
	cmd.flags = SD_CMD_SHORT;
	cmd.timeout = DEF_LOW_SPEED_CMD_TIMEOUT; //DEF_CMD_TIME_OUT;
	sdio_send_cmd(&cmd);
	cmd.err = sdio_wait_cmd_response(cmd.index);
	// why cmd41 always return crc fail?
	if (cmd.err != SD_OK && cmd.err != SD_CMD_CRC_FAIL)
	{
		SDCARD_WARN("send cmd41 err:%d\r\n", cmd.err);
		return cmd.err;
	}

	return SD_OK;
}

/*ask the CID number on the CMD line*/
// Manufacturer ID	        MID	    8	[127:120]
// OEM/Application          ID	OID	16	[119:104]
// Product name	            PNM	    40	[103:64]
// Product revision	        PRV	    8	[63:56]
// Product serial number	PSN	    32	[55:24]
// reserved	                --	    4	[23:20]
// Manufacturing date	    MDT	    12	[19:8]
static SDIO_Error sdcard_cmd2_process(void)
{
	SDIO_CMD_S cmd;

	cmd.index = ALL_SEND_CID;
	cmd.arg = 0;
	cmd.flags = SD_CMD_LONG;
	cmd.timeout = DEF_LOW_SPEED_CMD_TIMEOUT; // DEF_CMD_TIME_OUT;
	sdio_send_cmd(&cmd);
	cmd.err = sdio_wait_cmd_response(cmd.index);

	// dismiss the CID info

	return cmd.err;
}

static SDIO_Error sdcard_mmc_cmd3_process(void)
{
	SDIO_CMD_S cmd;

	cmd.index = SEND_RELATIVE_ADDR;
#if 0
    cmd.arg = 0;
#else
	sdcard.card_rca = 1;
	cmd.arg = (sdcard.card_rca << 16);
#endif
	cmd.flags = SD_CMD_SHORT;
	cmd.timeout = DEF_LOW_SPEED_CMD_TIMEOUT; //DEF_CMD_TIME_OUT;

	sdio_send_cmd(&cmd);
	cmd.err = sdio_wait_cmd_response(cmd.index);

	if (cmd.err == SD_CMD_RSP_TIMEOUT)
	{
		SDCARD_WARN("mmc cmd3 noresp \r\n");
		return SD_CMD_RSP_TIMEOUT;
	}
	else if (cmd.err == SD_CMD_CRC_FAIL)
	{
		SDCARD_WARN("mmc cmd3 cmdcrc err\r\n");
		return SD_CMD_CRC_FAIL;
	}

#if 0
    sdio_get_cmdresponse_argument(0, &cmd.resp[0]);
    sdcard.card_rca = (UINT16) (cmd.resp[0] >> 16);
#endif
	SDCARD_PRT("mmc cmd3 is ok, card rca:0x%x\r\n", sdcard.card_rca);
	return SD_OK;
}

/*ask the card to publish a new RCA*/
static SDIO_Error sdcard_cmd3_process(void)
{
	SDIO_CMD_S cmd;

	cmd.index = SEND_RELATIVE_ADDR;
	cmd.arg = 0;
	cmd.flags = SD_CMD_SHORT;
	cmd.timeout = DEF_LOW_SPEED_CMD_TIMEOUT; //DEF_CMD_TIME_OUT;

	sdio_send_cmd(&cmd);
	cmd.err = sdio_wait_cmd_response(cmd.index);

	if (cmd.err == SD_CMD_RSP_TIMEOUT)
	{
		SDCARD_WARN("cmd3 noresp \r\n");
		return SD_CMD_RSP_TIMEOUT;
	}
	else if (cmd.err == SD_CMD_CRC_FAIL)
	{
		SDCARD_WARN("cmd3 cmdcrc err\r\n");
		return SD_CMD_CRC_FAIL;
	}

	sdio_get_cmdresponse_argument(0, &cmd.resp[0]);
	sdcard.card_rca = (uint16_t)(cmd.resp[0] >> 16);
	SDCARD_PRT("cmd3 is ok, card rca:0x%x\r\n", sdcard.card_rca);
	return SD_OK;
}

#define SD_CARD 0
#define MMC_CARD 1
/*get CSD Register content*/
static SDIO_Error sdcard_cmd9_process(uint8_t card_type)
{
	SDIO_CMD_S cmd;
	int mult, csize;

	cmd.index = SEND_CSD;
	cmd.arg = (uint32_t)(sdcard.card_rca << 16);
	cmd.flags = SD_CMD_LONG;
	cmd.timeout = DEF_HIGH_SPEED_CMD_TIMEOUT; //DEF_CMD_TIME_OUT;

	sdio_send_cmd(&cmd);
	cmd.err = sdio_wait_cmd_response(cmd.index);
	if (cmd.err != SD_OK)
	{
		return cmd.err;
	}

	sdio_get_cmdresponse_argument(0, &cmd.resp[0]);
	sdio_get_cmdresponse_argument(1, &cmd.resp[1]);
	sdio_get_cmdresponse_argument(2, &cmd.resp[2]);

	sdcard.block_size = 1 << ((cmd.resp[1] >> 16) & 0xf);
	//os_printf("arg:%x %x %x %x size:%x\r\n", cmd.resp[0],
	//          cmd.resp[1], cmd.resp[2], cmd.resp[3], sdcard.block_size);

	if (card_type == SD_CARD)
	{

		if (((cmd.resp[0] >> 30) & 0x3) == 0)
		{
			csize = (((cmd.resp[1] & 0x3FF) << 2) | ((cmd.resp[2] >> 30) & 0x3));
			mult = (cmd.resp[2] >> 15) & 0x7;

			sdcard.total_block = (csize + 1) * (1 << (mult + 2));
			sdcard.total_block *= (sdcard.block_size >> 9);
		}
		else
		{
			csize = (((cmd.resp[1] & 0x3F) << 16) | ((cmd.resp[2] >> 16) & 0xFFFF));
			sdcard.total_block = (csize + 1) * 1024;
		}

		os_printf("size:%x total_block:%x\r\n", sdcard.block_size, sdcard.total_block);
	}
	else
	{
		if (sdcard.Addr_shift_bit != 0)
		{
			csize = (((cmd.resp[1] & 0x3FF) << 2) | ((cmd.resp[2] >> 30) & 0x3));
			mult = (cmd.resp[2] >> 15) & 0x7;

			sdcard.total_block = (csize + 1) * (1 << (mult + 2));
			sdcard.total_block *= (sdcard.block_size >> 9);
		}
		else
		{
			sdcard.total_block = 0;
		}
	}

	sdcard.block_size = SD_DEFAULT_BLOCK_SIZE;
	SDCARD_PRT("Bsize:%x;Total_block:%x\r\n", sdcard.block_size, sdcard.total_block);
	//ASSERT_ERR(sdcard.block_size == SD_DEFAULT_BLOCK_SIZE);

	return SD_OK;
}

/*select/deselect card*/
static SDIO_Error sdcard_cmd7_process(void)
{
	SDIO_CMD_S cmd;

	cmd.index = SELECT_CARD;
	cmd.arg = (uint32_t)(sdcard.card_rca << 16);
	cmd.flags = SD_CMD_SHORT;
	cmd.timeout = DEF_HIGH_SPEED_CMD_TIMEOUT; // DEF_CMD_TIME_OUT;

	sdio_send_cmd(&cmd);
	cmd.err = sdio_wait_cmd_response(cmd.index);
	return cmd.err;
}

/*set bus width*/
static SDIO_Error sdcard_acmd6_process(void)
{
	SDIO_CMD_S cmd;
	cmd.index = APP_CMD;
	cmd.arg = (uint32_t)(sdcard.card_rca << 16);
	cmd.flags = SD_CMD_SHORT;
	cmd.timeout = DEF_HIGH_SPEED_CMD_TIMEOUT; // DEF_CMD_TIME_OUT;
	sdio_send_cmd(&cmd);
	cmd.err = sdio_wait_cmd_response(cmd.index);
	if (cmd.err != SD_OK)
		return cmd.err;

	cmd.index = SWITCH_FUNC;
#ifdef CONFIG_SDCARD_BUSWIDTH_4LINE
	cmd.arg = 2;
#else
	cmd.arg = 0;
#endif
	cmd.flags = SD_CMD_SHORT;
	cmd.timeout = DEF_HIGH_SPEED_CMD_TIMEOUT; //DEF_CMD_TIME_OUT;

	sdio_send_cmd(&cmd);
	cmd.err = sdio_wait_cmd_response(cmd.index);

	return cmd.err;
}

/**************************************************
static SDIO_Error sdcard_cmd18_process(uint32_t addr)
{
    SDIO_CMD_S cmd;

    cmd.index = 18;
    cmd.arg = addr;
    cmd.flags = SD_CMD_SHORT;
    cmd.timeout = 0x90000;
    sdio_send_cmd(&cmd);
    cmd.err = sdio_wait_cmd_response(cmd.index);
    return cmd.err;
}
*****************************************************/
static SDIO_Error sdcard_cmd12_process(uint32_t addr)
{
	SDIO_CMD_S cmd;

	cmd.index = 12;
	cmd.arg = addr;
	cmd.flags = SD_CMD_SHORT;
	cmd.timeout = DEF_CMD_TIME_OUT;
	sdio_send_cmd(&cmd);
	cmd.err = sdio_wait_cmd_response(cmd.index);
	return cmd.err;
}

/***********************************************
static SDIO_Error sdcard_cmd17_process(uint32_t addr)
{
    SDIO_CMD_S cmd;

    cmd.index = 17;
    cmd.arg = addr;
    cmd.flags = SD_CMD_SHORT;
    cmd.timeout = 0x90000;
    sdio_send_cmd(&cmd);
    cmd.err = sdio_wait_cmd_response(cmd.index);
    return cmd.err;
}
**************************************************/

void sdcard_uninitialize(void)
{
	sdio_hw_uninit();
	sdio_sw_init();
	NoneedInitflag = 0;
}

void sdcard_get_card_info(SDCARD_S *card_info)
{
	card_info->total_block = sdcard.total_block;
	card_info->block_size = sdcard.block_size;
	card_info->card_rca = sdcard.card_rca;
	card_info->init_flag = sdcard.init_flag;
	card_info->Addr_shift_bit = sdcard.Addr_shift_bit;
}
SDIO_Error sdcard_read_single_block(uint8_t *readbuff, uint32_t readaddr, uint32_t blocksize)
{
	SDIO_CMD_S cmd;
	SDIO_Error ret;
	uint32_t sd_data0;

#if (CFG_SD_HOST_INTF == SD1_HOST_INTF)
	sd_data0 = 39;
#else
	sd_data0 = 10;
#endif
	gpio_config(sd_data0, 3);
	while (!gpio_input(sd_data0))
		;
	gpio_config(sd_data0, 2);
	sdio_clk_config(1);

	REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL, 0xffffffff);
	// setup data reg first
	sdio_set_data_timeout(DEF_HIGH_SPEED_CMD_TIMEOUT); //DEF_DATA_TIME_OUT);
	sdio_setup_data(SDIO_RD_DATA, blocksize);

	cmd.index = READ_SINGLE_BLOCK;
	cmd.arg = (uint32_t)(readaddr << sdcard.Addr_shift_bit);
	cmd.flags = SD_CMD_SHORT;
	cmd.timeout = DEF_HIGH_SPEED_CMD_TIMEOUT; // DEF_CMD_TIME_OUT;
	sdio_send_cmd(&cmd);
	cmd.err = sdio_wait_cmd_response(cmd.index);

	ret = cmd.err;

	if (ret == SD_CMD_RSP_TIMEOUT)
	{
		SDCARD_FATAL("cmd17 noresp, readsingle block err\r\n");
		goto read_return;
	}
	else if (ret == SD_CMD_CRC_FAIL)
	{
		SDCARD_FATAL("cmd17 cmdcrc err, readsingle block err\r\n");
		goto read_return;
	}

	cmd.err = sdcard_wait_receive_data(readbuff);
	ret = cmd.err;

	if (ret != SD_OK)
	{
		SDCARD_FATAL("read single block wait data receive err:%d\r\n", cmd.err);
		goto read_return;
	}
read_return:
	sdio_clk_config(0);
	return ret;
}

SDIO_Error sdcard_write_single_block(uint32_t *writebuff, uint32_t writeaddr)
{
	int i, ret;
	SDIO_CMD_S cmd;
	uint32_t tmpval, reg, sd_data0;

#if (CFG_SD_HOST_INTF == SD1_HOST_INTF)
	sd_data0 = 39;
#else
	sd_data0 = 10;
#endif
	gpio_config(sd_data0, 3);
	while (!gpio_input(sd_data0))
		;
	gpio_config(sd_data0, 2);

	sdio_clk_config(1);

	reg = REG_READ(REG_SDCARD_DATA_REC_CTRL);
	reg &= (~((1 << 16) | (1 << 0) | (1 << 1) | (1 << 3)));
	REG_WRITE(REG_SDCARD_DATA_REC_CTRL, reg);

	REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL, 0xffffffff);

	reg = REG_READ(REG_SDCARD_FIFO_THRESHOLD);
	REG_WRITE(REG_SDCARD_FIFO_THRESHOLD, reg | SDCARD_FIFO_SD_STA_RST);

	reg &= (0xffff | (SDCARD_FIFO_SD_RATE_SELECT_MASK << SDCARD_FIFO_SD_RATE_SELECT_POSI));
	reg |= (0x0101 /*| SDCARD_FIFO_TX_FIFO_RST*/);
	REG_WRITE(REG_SDCARD_FIFO_THRESHOLD, reg);

	i = 0;
	while (REG_READ(REG_SDCARD_FIFO_THRESHOLD) & SDCARD_FIFO_TXFIFO_WR_READY)
	{
		tmpval = (writebuff[i] << 24) | (writebuff[i + 1] << 16) | (writebuff[i + 2] << 8) | writebuff[i + 3];
		REG_WRITE(REG_SDCARD_WR_DATA_ADDR, tmpval);
		i += 4;
		if (SD_DEFAULT_BLOCK_SIZE <= i)
		{
			break;
		}
	}

	cmd.index = 24; //WRITE_MULTIPLE_BLOCK;
	cmd.arg = (uint32_t)(writeaddr << sdcard.Addr_shift_bit);
	cmd.flags = SD_CMD_SHORT;
	cmd.timeout = DEF_HIGH_SPEED_CMD_TIMEOUT; //DEF_CMD_TIME_OUT;
	sdio_send_cmd(&cmd);

	cmd.err = sdio_wait_cmd_response(cmd.index);
	ret = cmd.err;

	if (SD_OK == ret)
	{
		REG_WRITE(REG_SDCARD_DATA_REC_TIMER, DEF_HIGH_SPEED_DATA_TIMEOUT * 5);
		reg = (1 << 16) | (0 << 3) | (512 << 4) | (1 << 17)
#ifdef CONFIG_SDCARD_BUSWIDTH_4LINE
			  | SDCARD_DATA_REC_CTRL_DATA_BUS
#endif
			;
		REG_WRITE(REG_SDCARD_DATA_REC_CTRL, reg);

		do
		{
			reg = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);
		} while (!(reg & SDCARD_CMDRSP_TX_FIFO_NEED_WRITE));

		while (1)
		{
			reg = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);

			if (reg & (SDCARD_CMDRSP_DATA_TIME_OUT_INT))
			{
				ret = SD_ERROR;
				break;
			}

			if (reg & SDCARD_CMDRSP_DATA_WR_END_INT)
			{
				if (2 != ((reg & SDCARD_CMDRSP_WR_STATU) >> 20))
				{
					ret = SD_ERROR;
				}
				else
				{
					ret = SD_OK;
				}
				break;
			}
		}
		reg = REG_READ(REG_SDCARD_DATA_REC_CTRL);
		reg &= (~((1 << 16) | (1 << 0) | (1 << 1) | (1 << 3))
#ifdef CONFIG_SDCARD_BUSWIDTH_4LINE
				| SDCARD_DATA_REC_CTRL_DATA_BUS
#endif
		);
		REG_WRITE(REG_SDCARD_DATA_REC_CTRL, reg);
	}

	if (ret != SD_OK)
	{
		SDCARD_FATAL("--single blk write err:%d---\r\n", ret);
	}
	sdio_clk_config(0);

	return ret;
}

#if 1
static void sdcard_read_data_init(int blocknum)
{
	uint32_t reg, sd_data0;

#if (CFG_SD_HOST_INTF == SD1_HOST_INTF)
	sd_data0 = 39;
#else
	sd_data0 = 10;
#endif

	gpio_config(sd_data0, 3);
	while (!gpio_input(sd_data0))
		;
	gpio_config(sd_data0, 2);

	SDCARD_PRT("sdcard initial\r\n");
	sdio_clk_config(1);
	reg = DEF_HIGH_SPEED_CMD_TIMEOUT * blocknum;
	REG_WRITE(REG_SDCARD_DATA_REC_TIMER, reg);
	REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL, 0xFFFFFFFF);
	reg = REG_READ(REG_SDCARD_FIFO_THRESHOLD);
	reg &= ~(0xFFFF | (1 << 16) | (1 << 20));
	reg |= (0x0101 | ((1 << 16) | (1 << 20)));
	REG_WRITE(REG_SDCARD_FIFO_THRESHOLD, reg);

#ifdef CONFIG_SDCARD_BUSWIDTH_4LINE
	reg = 0x1 | (1 << 2) | (1 << 3) | (512 << 4) | (1 << 17);
	REG_WRITE(REG_SDCARD_DATA_REC_CTRL, reg);
#else
	reg = 0x1 | (0 << 2) | (1 << 3) | (512 << 4) | (1 << 17);
	REG_WRITE(REG_SDCARD_DATA_REC_CTRL, reg);
#endif
}
static SDIO_Error sdcard_cmd18_process(int block_addr)
{
	SDIO_CMD_S cmd;
	int Ret = SD_OK;

	cmd.index = 18;
	cmd.arg = (uint32_t)(block_addr << sdcard.Addr_shift_bit);
	cmd.flags = SD_CMD_SHORT;
	cmd.timeout = DEF_HIGH_SPEED_CMD_TIMEOUT; // DEF_CMD_TIME_OUT;
	sdio_send_cmd(&cmd);
	cmd.err = sdio_wait_cmd_response(cmd.index);

	Ret = cmd.err;
	return Ret;
}

static SDIO_Error sdcard_send_read_stop(void)
{
	//send stop command
	int reg, Ret;
	Ret = 0;

	reg = REG_READ(REG_SDCARD_FIFO_THRESHOLD);
	reg &= ~(0xFFFF | (1 << 16) | (1 << 20));
	reg |= (0x0101 | ((1 << 16) | (1 << 20)));
	REG_WRITE(REG_SDCARD_FIFO_THRESHOLD, reg);
	Ret = sdcard_cmd12_process(DEF_HIGH_SPEED_CMD_TIMEOUT);

	//close clock
	sdio_clk_config(0);
	return Ret;
}

static int sdcard_recev_data(uint8_t *read_data, uint32_t blcok_size)
{
	int i, Ret, reg, size;
	Ret = 0;
	i = 0;

	size = blcok_size << 9; /* *512*/
	;

	while (1)
	{
		reg = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);
		if (reg & SDCARD_CMDRSP_DATA_REC_END_INT)
		{
			REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL, SDCARD_CMDRSP_DATA_REC_END_INT);
			if (reg & SDCARD_CMDRSP_DATA_CRC_FAIL)
			{
				Ret = SD_DATA_CRC_FAIL;
			}

			// read 512 byte once time
			while (1)
			{
				reg = REG_READ(REG_SDCARD_FIFO_THRESHOLD);
				if (reg & SDCARD_FIFO_RXFIFO_RD_READY)
				{
					reg = REG_READ(REG_SDCARD_RD_DATA_ADDR);
					*(read_data + i++) = reg & 0xff;
					*(read_data + i++) = (reg >> 8) & 0xff;
					*(read_data + i++) = (reg >> 16) & 0xff;
					*(read_data + i++) = (reg >> 24) & 0xff;
					if ((i % 512) == 0)
						break;
				}
			}

			if (SDOnline == SD_CARD_OFFLINE)
			{
				//send stop command
				Ret += sdcard_send_read_stop();

				if (Ret != SD_OK)
				{
					SDCARD_FATAL("===read: send cmd12 error%d===\r\n", Ret);
				}

				break;
			}

			if (i >= size)
			{
				break;
			}
		}
		else
		{
			if (reg & SDCARD_CMDRSP_DATA_TIME_OUT_INT)
			{
				Ret = SD_DATA_TIMEOUT;
				break;
			}
		}
	}
	return Ret;
}

static SDIO_Error sdcard_cmd25_process(int block_addr)
{
	SDIO_CMD_S cmd;
	int ret = SD_OK;
	uint32_t reg, sd_data0;

#if (CFG_SD_HOST_INTF == SD1_HOST_INTF)
	sd_data0 = 39;
#else
	sd_data0 = 10;
#endif

	gpio_config(sd_data0, 3);
	while (!gpio_input(sd_data0))
		;
	gpio_config(sd_data0, 2);

	sdio_clk_config(1);
	REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL, 0xffffffff);
	reg = REG_READ(REG_SDCARD_FIFO_THRESHOLD);

	REG_WRITE(REG_SDCARD_FIFO_THRESHOLD, reg | SDCARD_FIFO_SD_STA_RST);

	reg |= (0x0101 | SDCARD_FIFO_TX_FIFO_RST);
	REG_WRITE(REG_SDCARD_FIFO_THRESHOLD, reg);

	cmd.index = 25; //WRITE_MULTIPLE_BLOCK;
	cmd.arg = (uint32_t)(block_addr << sdcard.Addr_shift_bit);
	cmd.flags = SD_CMD_SHORT;
	cmd.timeout = DEF_HIGH_SPEED_CMD_TIMEOUT; //DEF_CMD_TIME_OUT;
	sdio_send_cmd(&cmd);

	cmd.err = sdio_wait_cmd_response(cmd.index);

	ret = cmd.err;
	return ret;
}

/*********************************write:second phase********************************/
static SDIO_Error sdcard_write_data(uint8_t *write_data, uint32_t blcok_size, uint8_t first_data_after_cmd)
{
	int i, j, tmpval, reg, ret;

	i = 0;
	ret = 0;

	if (1 == first_data_after_cmd)
	{
		// 1. fill the first block to fifo and start write data enable
		while (REG_READ(REG_SDCARD_FIFO_THRESHOLD) & SDCARD_FIFO_TXFIFO_WR_READY)
		{
			tmpval = (write_data[i] << 24) | (write_data[i + 1] << 16) | (write_data[i + 2] << 8) | write_data[i + 3];
			REG_WRITE(REG_SDCARD_WR_DATA_ADDR, tmpval);
			i += 4;
			if (SD_DEFAULT_BLOCK_SIZE <= i)
			{
				break;
			}
		}
		reg = REG_READ(REG_SDCARD_CMD_RSP_INT_MASK);
		reg |= SDCARD_CMDRSP_TX_FIFO_EMPTY_MASK;
		REG_WRITE(REG_SDCARD_CMD_RSP_INT_MASK, reg);

		REG_WRITE(REG_SDCARD_DATA_REC_TIMER, DEF_HIGH_SPEED_DATA_TIMEOUT * blcok_size);
		reg = (SD_DEFAULT_BLOCK_SIZE << SDCARD_DATA_REC_CTRL_BLK_SIZE_POSI) |
			  SDCARD_DATA_REC_CTRL_DATA_MUL_BLK | SDCARD_DATA_REC_CTRL_DATA_BYTE_SEL |
			  SDCARD_DATA_REC_CTRL_DATA_WR_DATA_EN
#ifdef CONFIG_SDCARD_BUSWIDTH_4LINE
			  | SDCARD_DATA_REC_CTRL_DATA_BUS
#endif
			;
		REG_WRITE(REG_SDCARD_DATA_REC_CTRL, reg);

		do
		{
			reg = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);
		} while (!(reg & SDCARD_CMDRSP_TX_FIFO_NEED_WRITE));

		blcok_size -= 1;
	}

	// 2. write other blocks
	while (blcok_size)
	{
		blcok_size--;
		j = 0;
		while (j < SD_DEFAULT_BLOCK_SIZE)
		{
			if (REG_READ(REG_SDCARD_FIFO_THRESHOLD) & SDCARD_FIFO_TXFIFO_WR_READY)
			{
				tmpval = (write_data[i] << 24) | (write_data[i + 1] << 16) | (write_data[i + 2] << 8) | write_data[i + 3];
				REG_WRITE(REG_SDCARD_WR_DATA_ADDR, tmpval);
				i += 4;
				j += 4;
			}
		}

		do
		{
			reg = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);
		} while (!(reg & SDCARD_CMDRSP_DATA_WR_END_INT));
		REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL, SDCARD_CMDRSP_DATA_WR_END_INT);

		do
		{
			reg = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);
		} while (!(reg & SDCARD_CMDRSP_TX_FIFO_NEED_WRITE));

		if (2 != ((reg & SDCARD_CMDRSP_WR_STATU) >> 20))
		{
			ret = SD_ERROR;
			os_printf("write data error !!!\r\n");
			break;
		}
	}

	return ret;
}

static SDIO_Error sdcard_send_write_stop(int err)
{
	int reg, ret, sd_data0;

#if (CFG_SD_HOST_INTF == SD1_HOST_INTF)
	sd_data0 = 39;
#else
	sd_data0 = 14;
#endif

	// 3. after the last block,write zero
	while (1)
	{
		reg = REG_READ(REG_SDCARD_FIFO_THRESHOLD);
		if (reg & SDCARD_FIFO_TXFIFO_WR_READY)
		{
			REG_WRITE(REG_SDCARD_WR_DATA_ADDR, 0);
			break;
		}
	}
	// 4.wait and clear flag
	do
	{
		reg = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);
		if (reg & (SDCARD_CMDRSP_DATA_BUSY | SDCARD_CMDRSP_DATA_WR_END_INT))
			break;
	} while (1); //BUSY

	if ((reg & SDCARD_CMDRSP_DATA_BUSY))
	{
		reg = REG_READ(REG_SDCARD_CMD_RSP_INT_MASK);
		reg &= ~SDCARD_CMDRSP_TX_FIFO_EMPTY_MASK;
		REG_WRITE(REG_SDCARD_CMD_RSP_INT_MASK, reg);
	}
	if ((reg & SDCARD_CMDRSP_DATA_WR_END_INT))
	{
		REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL, SDCARD_CMDRSP_DATA_WR_END_INT);
	}

	reg = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);
	if (2 != ((reg & SDCARD_CMDRSP_WR_STATU) >> 20))
	{
		ret = SD_ERROR;
	}
	else
	{
		ret = SD_OK;
	}

	reg = REG_READ(REG_SDCARD_FIFO_THRESHOLD);
	reg |= SDCARD_FIFO_TX_FIFO_RST;
	REG_WRITE(REG_SDCARD_FIFO_THRESHOLD, reg);
	reg = REG_READ(REG_SDCARD_CMD_RSP_INT_MASK);
	reg &= ~SDCARD_CMDRSP_TX_FIFO_EMPTY_MASK;
	REG_WRITE(REG_SDCARD_CMD_RSP_INT_MASK, reg);

	gpio_config(sd_data0, 3);
	while (!gpio_input(sd_data0))
		;
	gpio_config(sd_data0, 2);

	ret += sdcard_cmd12_process(DEF_HIGH_SPEED_CMD_TIMEOUT);
	if (ret != SD_OK)
	{
		SDCARD_FATAL("===write err:%x,====\r\n", ret);
	}
	ret += err;

	return ret;
}

SDIO_Error sdcard_read_multi_block(uint8_t *read_buff, int first_block, int block_num)
{
	int ret = SD_OK;
	uint8_t op_flag = 0;

	if (SDIO_WR_flag == SDIO_WR_DATA)
	{
		op_flag = 1; //write stop
	}
	else
	{
		if (last_WR_addr == first_block)
		{
			op_flag = 0; //continue read
		}
		else
		{
			op_flag = 2; //read stop
		}

		if (1 == no_need_send_cmd12_flag)
			op_flag = 3; //stop has send
	}

	os_printf("===sd read: start = %x,block = %x,op_flag = %x=====\r\n", first_block, block_num, op_flag);

	no_need_send_cmd12_flag = 0;
	if (0 == op_flag)
	{
		ret = sdcard_recev_data(read_buff, block_num);
	}
	else
	{
		if (1 == op_flag)
		{
			ret = sdcard_send_write_stop(0);
		}
		else if (2 == op_flag)
		{
			ret = sdcard_send_read_stop();
		}
		sdcard_read_data_init(block_num);
		ret += sdcard_cmd18_process(first_block);
		if (SD_OK == ret)
		{
			ret = sdcard_recev_data(read_buff, block_num);
		}
	}

	if (SD_OK != ret)
	{
		no_need_send_cmd12_flag = 1;
		ret += sdcard_send_read_stop();
	}
	SDIO_WR_flag = SDIO_RD_DATA;
	last_WR_addr = first_block + block_num;
	return ret;
}

SDIO_Error sdcard_write_multi_block(uint8_t *write_buff, uint32_t first_block, uint32_t block_num)
{
	uint8_t ret = SD_OK;
	uint8_t op_flag = 0;
	if (SDIO_WR_flag == SDIO_RD_DATA)
	{
		op_flag = 1; //read stop
	}
	else
	{
		if (last_WR_addr == first_block)
		{
			op_flag = 0; //continue write
		}
		else
		{
			op_flag = 2; //write stop
		}

		if (1 == no_need_send_cmd12_flag)
			op_flag = 3; //stop has send
	}
	os_printf("===sd write: start = %x,block = %x,op_flag = %x=====\r\n", first_block, block_num, op_flag);

	no_need_send_cmd12_flag = 0;
	if (0 == op_flag) //continue write
	{
		ret = sdcard_write_data(write_buff, block_num, 0);
	}
	else
	{
		if (1 == op_flag)
		{
			/************if last state is single read:not send stop;***************/
			ret = sdcard_send_read_stop();
		}
		else if (op_flag == 2)
		{
			ret = sdcard_send_write_stop(0);
		}

		ret += sdcard_cmd25_process(first_block);
		if (SD_OK == ret)
		{
			ret += sdcard_write_data(write_buff, block_num, 1);
		}
		else
		{
			SDCARD_FATAL("--cmd25 send error:ret=%d\r\n", ret);
		}
	}
	if (ret != SD_OK)
	{
		ret += sdcard_send_write_stop(ret);
		no_need_send_cmd12_flag = 1;
	}
	last_WR_addr = first_block + block_num;
	SDIO_WR_flag = SDIO_WR_DATA;
	return ret;
}
#endif

#if 0

SDIO_Error sdcard_read_multi_block(uint8 *read_buff, int first_block, int block_num)
{
    int Ret = SD_OK;
	unsigned int i;
	SDIO_CMD_S cmd;
	uint32 reg,sd_data0;
	os_printf("----read:0x%x, num:%d\r\n",first_block,block_num);

	SDIO_WR_flag = 	SDIO_RD_DATA;

#if (CFG_SD_HOST_INTF == SD1_HOST_INTF)
	sd_data0 = 39;
#else
	sd_data0 = 10;
#endif
	gpio_config(sd_data0, 3);
	while(!gpio_input(sd_data0));
	gpio_config(sd_data0, 2);

    sdio_clk_config(1);
    reg  = DEF_HIGH_SPEED_CMD_TIMEOUT * block_num;
	REG_WRITE(REG_SDCARD_DATA_REC_TIMER,reg);
	REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL,0xFFFFFFFF);
	reg = REG_READ(REG_SDCARD_FIFO_THRESHOLD);
	reg &= ~(0xFFFF | (1 << 16) | (1 << 20));
    reg  |= (0x0101 | ((1 << 16) | (1 << 20)));
	REG_WRITE(REG_SDCARD_FIFO_THRESHOLD,reg);

#ifdef CONFIG_SDCARD_BUSWIDTH_4LINE
    reg = 0x1|(1 << 2)|(1 << 3)|(512 << 4)|(1<< 17);
	REG_WRITE(REG_SDCARD_DATA_REC_CTRL,reg);
#else
    reg = 0x1|(0 << 2)|(1 << 3)|(512 << 4)|(1<< 17);
	REG_WRITE(REG_SDCARD_DATA_REC_CTRL,reg);
#endif

   // if((SD_CARD == Sd_MMC_flag)&&(driver_sdcard.total_block > 0x100000))
	{
        cmd.index = 18;
	    cmd.arg = (uint32)(first_block << sdcard.Addr_shift_bit);
	    cmd.flags = SD_CMD_SHORT;
	    cmd.timeout = DEF_HIGH_SPEED_CMD_TIMEOUT;// DEF_CMD_TIME_OUT;
	    sdio_send_cmd(&cmd);
	    cmd.err = sdio_wait_cmd_response(cmd.index);

		Ret = cmd.err;
	}
    if(Ret == SD_OK)
    {
        unsigned int size = SD_DEFAULT_BLOCK_SIZE  * block_num;
        //reveive data
        i = 0;
        while(1)
        {
			reg = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);
			if(reg & SDCARD_CMDRSP_DATA_REC_END_INT)
			{
				REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL,SDCARD_CMDRSP_DATA_REC_END_INT);
				if(reg & SDCARD_CMDRSP_DATA_CRC_FAIL)
				{
					Ret = SD_DATA_CRC_FAIL;
				}

				// read not change
				while(1)
				{
					reg = REG_READ(REG_SDCARD_FIFO_THRESHOLD);
		            if(reg & SDCARD_FIFO_RXFIFO_RD_READY)
		            {
		            	reg = REG_READ(REG_SDCARD_RD_DATA_ADDR);
						*(read_buff+i++) = reg & 0xff;
				        *(read_buff+i++) = (reg >> 8) & 0xff;
				        *(read_buff+i++) = (reg >> 16) & 0xff;
				        *(read_buff+i++) = (reg >> 24) & 0xff;
						if((i%512) == 0)
							break;
		            }
				}
				if(i >= size)
	            {
	                break;
	            }
            }
            else
            {
                if(reg & SDCARD_CMDRSP_DATA_TIME_OUT_INT)
                {
                    Ret = SD_DATA_TIMEOUT;
                    break;
                }
            }
        }
	}

	//stop
	reg = REG_READ(REG_SDCARD_FIFO_THRESHOLD);
	reg &= ~(0xFFFF | (1 << 16) | (1 << 20));
	reg |= (0x0101 | ((1 << 16) | (1 << 20)));
	REG_WRITE(REG_SDCARD_FIFO_THRESHOLD,reg);
	Ret += sdcard_cmd12_process(DEF_HIGH_SPEED_CMD_TIMEOUT);

    sdio_clk_config(0);

    if(Ret != SD_OK)
    {
        os_printf("SD Ret:%d\r\n",Ret);
    }
    return Ret;
}
#endif

#if 0
SDIO_Error sdcard_write_multi_block(uint8 *write_buff, uint32 first_block, uint32 block_num)
{
    SDIO_CMD_S cmd;
	int ret;
    uint32 i,j,reg,tmpval,sd_data0;
	//GLOBAL_INT_DECLARATION();

#if (CFG_SD_HOST_INTF == SD1_HOST_INTF)
	sd_data0 = 39;
#else
	sd_data0 = 10;
#endif
	gpio_config(sd_data0, 3);
	while(!gpio_input(sd_data0));
	gpio_config(sd_data0, 2);

	os_printf("__SD card multi write__:0x%x\r\n",first_block);

    sdio_clk_config(1);
    REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL, 0xffffffff);
    reg = REG_READ(REG_SDCARD_FIFO_THRESHOLD);

    REG_WRITE(REG_SDCARD_FIFO_THRESHOLD, reg|SDCARD_FIFO_SD_STA_RST);

    //reduce clk rate
    //sdio_set_low_clk();

    reg |= (0x0101 | SDCARD_FIFO_TX_FIFO_RST);
    REG_WRITE(REG_SDCARD_FIFO_THRESHOLD,reg);


    cmd.index = 25;//WRITE_MULTIPLE_BLOCK;
    cmd.arg = (uint32)(first_block << sdcard.Addr_shift_bit);
    cmd.flags = SD_CMD_SHORT;
    cmd.timeout =  DEF_HIGH_SPEED_CMD_TIMEOUT;//DEF_CMD_TIME_OUT;
    sdio_send_cmd(&cmd);

    cmd.err = sdio_wait_cmd_response(cmd.index);
    ret = cmd.err;

	SDCARD_PRT("ret = %d\r\n", ret);

    if(SD_OK == ret)
    {
		i = 0;
	    // 1. fill the first block to fifo and start write data enable
	    while( REG_READ(REG_SDCARD_FIFO_THRESHOLD) & SDCARD_FIFO_TXFIFO_WR_READY )
	    {
	        tmpval = (write_buff[i]<<24)|(write_buff[i+1]<< 16)|(write_buff[i+2]<<8)|write_buff[i+3];
	        REG_WRITE(REG_SDCARD_WR_DATA_ADDR, tmpval);
	        i += 4;
	        if(SD_DEFAULT_BLOCK_SIZE <= i)
	        {
	            break;
	        }
	    }
	    reg = REG_READ(REG_SDCARD_CMD_RSP_INT_MASK);
	    reg |= SDCARD_CMDRSP_TX_FIFO_EMPTY_MASK;
	    REG_WRITE(REG_SDCARD_CMD_RSP_INT_MASK,reg);

	    REG_WRITE(REG_SDCARD_DATA_REC_TIMER,DEF_HIGH_SPEED_DATA_TIMEOUT * block_num);
	    reg = (SD_DEFAULT_BLOCK_SIZE << SDCARD_DATA_REC_CTRL_BLK_SIZE_POSI)|
	            SDCARD_DATA_REC_CTRL_DATA_MUL_BLK | SDCARD_DATA_REC_CTRL_DATA_BYTE_SEL |
	            SDCARD_DATA_REC_CTRL_DATA_WR_DATA_EN
#ifdef CONFIG_SDCARD_BUSWIDTH_4LINE
	           | SDCARD_DATA_REC_CTRL_DATA_BUS
#endif
			;
	    REG_WRITE(REG_SDCARD_DATA_REC_CTRL,reg);

	    do
	    {
	        reg = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);
	    }while(!(reg&SDCARD_CMDRSP_TX_FIFO_NEED_WRITE));

	    // 2. write other blocks
	    while(--block_num)
	    {
	        j = 0;
	        while(j < SD_DEFAULT_BLOCK_SIZE)
	        {
	            if(REG_READ(REG_SDCARD_FIFO_THRESHOLD) & SDCARD_FIFO_TXFIFO_WR_READY )
	            {
	                tmpval = (write_buff[i]<<24)|(write_buff[i+1]<<16)|(write_buff[i+2]<<8)|write_buff[i+3];
	                REG_WRITE(REG_SDCARD_WR_DATA_ADDR, tmpval);
	                i += 4;
	                j += 4;
	            }
	        }

	        do
	        {
	            reg = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);
	        }while(!(reg&SDCARD_CMDRSP_DATA_WR_END_INT));
	        REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL,SDCARD_CMDRSP_DATA_WR_END_INT);

	        do
	        {
	            reg = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);
	        }while(!(reg&SDCARD_CMDRSP_TX_FIFO_NEED_WRITE));

	        if(2 != ((reg & SDCARD_CMDRSP_WR_STATU)>>20))
	        {
	            ret = SD_ERROR;
				goto sndcmd12;
	        }
	    }

	    // 3. after the last block,write zero
	    //GLOBAL_INT_DISABLE();
	    while(1)
	    {
	        reg = REG_READ(REG_SDCARD_FIFO_THRESHOLD);
	        if(reg & SDCARD_FIFO_TXFIFO_WR_READY)
	        {
	            REG_WRITE(REG_SDCARD_WR_DATA_ADDR, 0);
	            break;
	        }
	    }
    // 4.wait and clear flag
		do
		{
			reg = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);
			if(reg &(SDCARD_CMDRSP_DATA_BUSY | SDCARD_CMDRSP_DATA_WR_END_INT))
				break;
		}while(1);  //BUSY

		if((reg&SDCARD_CMDRSP_DATA_BUSY))
		{
			reg = REG_READ(REG_SDCARD_CMD_RSP_INT_MASK);
		    reg &= ~SDCARD_CMDRSP_TX_FIFO_EMPTY_MASK;
		    REG_WRITE(REG_SDCARD_CMD_RSP_INT_MASK,reg);
		}
		if((reg&SDCARD_CMDRSP_DATA_WR_END_INT))
		{
			REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL,SDCARD_CMDRSP_DATA_WR_END_INT);
		}

		reg = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);
	    if(2 != ((reg & SDCARD_CMDRSP_WR_STATU)>>20))
		{
	        ret =  SD_ERROR;
	    }
		else
	    {
	    	ret =  SD_OK;
	    }
    }
	reg = REG_READ(REG_SDCARD_FIFO_THRESHOLD);
	reg |= SDCARD_FIFO_TX_FIFO_RST;
	REG_WRITE(REG_SDCARD_FIFO_THRESHOLD,reg);
    reg = REG_READ(REG_SDCARD_CMD_RSP_INT_MASK);
    reg &= ~SDCARD_CMDRSP_TX_FIFO_EMPTY_MASK;
    REG_WRITE(REG_SDCARD_CMD_RSP_INT_MASK,reg);

	//GLOBAL_INT_RESTORE();

	//os_printf("---SD card multi write OVER--\r\n");

	gpio_config(sd_data0, 3);
	while(!gpio_input(sd_data0));
	gpio_config(sd_data0, 2);
sndcmd12:
    ret += sdcard_cmd12_process(DEF_HIGH_SPEED_CMD_TIMEOUT);
	if(ret != SD_OK)
    {
        SDCARD_FATAL("===write err:%x,%x,%x====\r\n",first_block,ret, cmd.err);
    }
#if 0
	gpio_config(sd_data0, GMODE_INPUT_PULLUP);
	while(!gpio_input(sd_data0));
	gpio_config(sd_data0, GMODE_SECOND_FUNC_PULL_UP);
	sdio_clk_config(0);
#endif
    return ret;
}
#endif

#if 0
SDIO_Error sdcard_write_multi_block(uint8 *write_buff, uint32 first_block, uint32 block_num)
{
    SDIO_CMD_S cmd;
	int ret;
    uint32 i,j,reg,tmpval,sd_data0;
	//GLOBAL_INT_DECLARATION();

#if (CFG_SD_HOST_INTF == SD1_HOST_INTF)
	sd_data0 = 39;
#else
	sd_data0 = 10;
#endif
	gpio_config(sd_data0, 3);
	while(!gpio_input(sd_data0));
	gpio_config(sd_data0, 2);

	os_printf("__SD card multi write__:0x%x\r\n",first_block);


    sdio_clk_config(1);
    REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL, 0xffffffff);
    reg = REG_READ(REG_SDCARD_FIFO_THRESHOLD);

    REG_WRITE(REG_SDCARD_FIFO_THRESHOLD, reg|SDCARD_FIFO_SD_STA_RST|SDCARD_FIFO_SD_CLK_REC_SEL);

    //reduce clk rate
    //sdio_set_low_clk();

    reg |= (0x0101 | SDCARD_FIFO_TX_FIFO_RST);
    REG_WRITE(REG_SDCARD_FIFO_THRESHOLD,reg);


    cmd.index = 25;//WRITE_MULTIPLE_BLOCK;
    cmd.arg = (uint32)(first_block << sdcard.Addr_shift_bit);
    cmd.flags = SD_CMD_SHORT;
    cmd.timeout =  DEF_HIGH_SPEED_CMD_TIMEOUT;//DEF_CMD_TIME_OUT;
    sdio_send_cmd(&cmd);

    cmd.err = sdio_wait_cmd_response(cmd.index);
    ret = cmd.err;

	SDCARD_FATAL("ret = %d\r\n", ret);

    if(SD_OK == ret)
    {
		i = 0;
	    // 1. fill the first block to fifo and start write data enable
	    while( REG_READ(REG_SDCARD_FIFO_THRESHOLD) & SDCARD_FIFO_TXFIFO_WR_READY )
	    {
	        tmpval = (write_buff[i]<<24)|(write_buff[i+1]<< 16)|(write_buff[i+2]<<8)|write_buff[i+3];
	        REG_WRITE(REG_SDCARD_WR_DATA_ADDR, tmpval);
	        i += 4;
	        if(SD_DEFAULT_BLOCK_SIZE <= i)
	        {
	            break;
	        }
	    }
	    reg = REG_READ(REG_SDCARD_CMD_RSP_INT_MASK);
	    reg |= SDCARD_CMDRSP_TX_FIFO_EMPTY_MASK;
	    REG_WRITE(REG_SDCARD_CMD_RSP_INT_MASK,reg);

	    REG_WRITE(REG_SDCARD_DATA_REC_TIMER,DEF_HIGH_SPEED_DATA_TIMEOUT * block_num);
	    reg = (SD_DEFAULT_BLOCK_SIZE << SDCARD_DATA_REC_CTRL_BLK_SIZE_POSI)|
	            SDCARD_DATA_REC_CTRL_DATA_MUL_BLK | SDCARD_DATA_REC_CTRL_DATA_BYTE_SEL |
	            SDCARD_DATA_REC_CTRL_DATA_WR_DATA_EN
#ifdef CONFIG_SDCARD_BUSWIDTH_4LINE
	           | SDCARD_DATA_REC_CTRL_DATA_BUS
#endif
			;
	    REG_WRITE(REG_SDCARD_DATA_REC_CTRL,reg);

		REG_GPIO_0x1B = 0x00;
		REG_GPIO_0x1B = 0x02;

		do
		{
			reg = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);
		}while(!(reg&SDCARD_CMDRSP_DATA_WR_END_INT));
		REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL,SDCARD_CMDRSP_DATA_WR_END_INT);

		if(2 != ((reg & SDCARD_CMDRSP_WR_STATU)>>20))
		{
			ret = SD_ERROR;
			goto sndcmd12;
		}

		REG_GPIO_0x1B = 0x00;
		REG_GPIO_0x1B = 0x02;

	    // 2. write other blocks
	    while(--block_num)
	    {
	        j = 0;
	        while(j < SD_DEFAULT_BLOCK_SIZE)
	        {
	            if(REG_READ(REG_SDCARD_FIFO_THRESHOLD) & SDCARD_FIFO_TXFIFO_WR_READY )
	            {
	                tmpval = (write_buff[i]<<24)|(write_buff[i+1]<<16)|(write_buff[i+2]<<8)|write_buff[i+3];
	                REG_WRITE(REG_SDCARD_WR_DATA_ADDR, tmpval);
	                i += 4;
	                j += 4;
	            }
	        }

	        do
	        {
	            reg = REG_READ(REG_SDCARD_CMD_RSP_INT_SEL);
	        }while(!(reg&SDCARD_CMDRSP_DATA_WR_END_INT));
	        REG_WRITE(REG_SDCARD_CMD_RSP_INT_SEL,SDCARD_CMDRSP_DATA_WR_END_INT);

	        if(2 != ((reg & SDCARD_CMDRSP_WR_STATU)>>20))
	        {
	            ret = SD_ERROR;
				goto sndcmd12;
	        }
	    }

    }

	REG_GPIO_0x1B = 0x00;
	REG_GPIO_0x1B = 0x02;

	reg = REG_READ(REG_SDCARD_FIFO_THRESHOLD);
	reg |= SDCARD_FIFO_TX_FIFO_RST;
	REG_WRITE(REG_SDCARD_FIFO_THRESHOLD,reg);
    reg = REG_READ(REG_SDCARD_CMD_RSP_INT_MASK);
    reg &= ~SDCARD_CMDRSP_TX_FIFO_EMPTY_MASK;
    REG_WRITE(REG_SDCARD_CMD_RSP_INT_MASK,reg);

	//GLOBAL_INT_RESTORE();

	//os_printf("---SD card multi write OVER--\r\n");

	gpio_config(sd_data0, 3);
	while(!gpio_input(sd_data0));
	gpio_config(sd_data0, 2);
sndcmd12:
    ret += sdcard_cmd12_process(DEF_HIGH_SPEED_CMD_TIMEOUT);
	if(ret != SD_OK)
    {
        SDCARD_FATAL("===write err:%x,%x,%x====\r\n",first_block,ret, cmd.err);
    }

	reg = REG_READ(REG_SDCARD_FIFO_THRESHOLD);
	reg &= (~SDCARD_FIFO_SD_CLK_REC_SEL);
	REG_WRITE(REG_SDCARD_FIFO_THRESHOLD,reg);


    return ret;
}
#endif

#if 0
int sdcard_get_block_size(void)
{
    return sdcard.block_size;
}

void sdcard_idle(char enable)
{}

int sd_wr_mblk_sync(int first_block, int block_num, uint8* data)
{
    return sdcard_write_multi_block( data,  first_block,  block_num);
}


void clr_sd_noinitial_flag(void)
{
    NoneedInitflag = 0;
}
void clear_sd_attached(void)
{
	cnt_online = 0;
}

void clear_sd_detached(void)
{
    cnt_offline = 0;
}
#endif
int sd_rd_blk_sync_old(int first_block, int block_num, uint8_t *dest)
{
	return sdcard_read_multi_block(dest, first_block, block_num);
}

int sd_rd_blk_sync(int first_block, int block_num, uint8_t *dest)
{
	return sdcard_read_multi_block(dest, first_block, block_num);
}

SDIO_Error SD_init(void)
{
	os_printf("SD_init:\r\n");

	//REG_SYSTEM_0x5C &= (~(0x3F << 0));    //io voltage

	SDIO_Error err = SD_OK;
	sdio_sw_init();
	sys_delay_ms(20);
	sdio_hw_init();
	sys_delay_ms(30);

	// rest card
	err = sdcard_cmd0_process();
	if (err != SD_OK)
	{
		SDCARD_FATAL("send cmd0 err\r\n");
		goto err_return;
	}
	sys_delay_ms(5);

	sys_delay_ms(50);
	err = sdcard_cmd1_process();
	os_printf("cmd 1:%x \r\n", err);
	if (err == SD_OK)
	{
		goto MMC_init;
	}
	sys_delay_ms(5);

	// check support voltage
	err = sdcard_cmd8_process();
	if (err != SD_OK && err != SD_CMD_RSP_TIMEOUT)
	{
		SDCARD_FATAL("send cmd8 err\r\n");
		goto err_return;
	}

	if (err == SD_OK)
	{
		int retry_time = SD_MAX_VOLT_TRIAL;
		uint32_t resp0;
		while (retry_time)
		{
			err = sdcard_acmd41_process(SD_DEFAULT_OCR);
			if (err != SD_OK)
			{
				SDCARD_FATAL("send cmd55&cmd41 err:%d, quite loop\r\n", err);
				goto err_return;
			}
			sdio_get_cmdresponse_argument(0, &resp0);
			if (resp0 & OCR_MSK_BUSY)
			{
				if (resp0 & OCR_MSK_HC)
					sdcard.Addr_shift_bit = 0;
				else
					sdcard.Addr_shift_bit = 9;
				break;
			}

			sys_delay_ms(2);
			retry_time--;
		}
		if (!retry_time)
		{
			SDCARD_FATAL("send cmd55&cmd41 retry time out\r\n");
			return SD_INVALID_VOLTRANGE;
		}

		SDCARD_PRT("send cmd55&cmd41 complete, card is ready\r\n");

		if (resp0 & OCR_MSK_HC)
		{
			SDCARD_PRT("High Capacity SD Memory Card\r\n");
		}
		else
		{
			SDCARD_PRT("Standard Capacity SD Memory Card\r\n");
		}
	}
	else if (err == SD_CMD_RSP_TIMEOUT)
	{
		int retry_time = SD_MAX_VOLT_TRIAL;
		uint32_t resp0;
		while (retry_time)
		{
			err = sdcard_acmd41_process(OCR_MSK_VOLTAGE_ALL);
			if (err != SD_OK)
			{
				SDCARD_FATAL("send cmd55&cmd41 err, quite loop\r\n");
				goto err_return;
			}
			sdio_get_cmdresponse_argument(0, &resp0);
			if (resp0 & OCR_MSK_BUSY)
			{
				if (resp0 & OCR_MSK_HC)
					sdcard.Addr_shift_bit = 0;
				else
					sdcard.Addr_shift_bit = 9;
				break;
			}
			sys_delay_ms(2);
			retry_time--;
		}
		if (!retry_time)
		{
			SDCARD_FATAL("send cmd55&cmd41 retry time out, maybe a MMC card\r\n");
			err = SD_ERROR;
			goto err_return;
		}
		SDCARD_PRT("send cmd55&cmd41 complete, SD V1.X card is ready\r\n");
	}
	sys_delay_ms(2);
	// get CID, return R2
	err = sdcard_cmd2_process();
	if (err != SD_OK)
	{
		SDCARD_FATAL("send cmd2 err:%d\r\n", err);
		goto err_return;
	}
	sys_delay_ms(2);
	// get RCA,
	err = sdcard_cmd3_process();
	if (err != SD_OK)
	{
		SDCARD_FATAL("send cmd3 err:%d\r\n", err);
		goto err_return;
	}

	// change to high speed clk
	sdio_set_high_clk();
	sys_delay_ms(2);
	// get CSD
	err = sdcard_cmd9_process(SD_CARD);
	if (err != SD_OK)
	{
		SDCARD_FATAL("send cmd9 err:%d\r\n", err);
		goto err_return;
	}
	sys_delay_ms(2);
	// select card
	err = sdcard_cmd7_process();
	if (err != SD_OK)
	{
		SDCARD_FATAL("send cmd7 err:%d\r\n", err);
		goto err_return;
	}
	sys_delay_ms(2);
	// change bus width, for high speed
	err = sdcard_acmd6_process();
	if (err != SD_OK)
	{
		SDCARD_FATAL("send acmd6 err:%d\r\n", err);
		goto err_return;
	}

	// Sd_MMC_flag = SD_CARD;
	err = SD_OK;
	SDCARD_PRT("sdcard initialize is done\r\n");
	goto right_return;

MMC_init:
	err = sdcard_cmd2_process();
	os_printf("cmd 2 :%x\r\n", err);
	if (err != SD_OK)
		goto err_return;
	err = sdcard_mmc_cmd3_process();
	os_printf("cmd 3 :%x\r\n", err);
	sdio_set_high_clk();
	err = sdcard_cmd9_process(MMC_CARD);
	os_printf("cmd 9 :%x\r\n", err);
	if (sdcard.Addr_shift_bit == 0)
	{
		err = sdcard_mmc_cmd8_process();
		os_printf("cmd 8 :%x\r\n", err);
	}
	if (err != SD_OK)
		goto err_return;
	err = sdcard_cmd7_process();
	if (err != SD_OK)
		goto err_return;
	// Sd_MMC_flag = MMC_CARD;
	goto right_return;

right_return:

	Sd_MMC_flag = SD_CARD;
	NoneedInitflag = 1;

	sd_rd_blk_sync_fptr = sd_rd_blk_sync_old;

err_return:
	sdio_clk_config(0);
	return err;
}

FATFS *Fatfs_buf;
//FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw);
#define SD_TEST_SIZE 8 * 512

void sd_test_write(void)
{
#define TEST_TXT_FILE_NAME "/test1.txt"

	unsigned char *pbuf;
	unsigned char *read_buf;
	TCHAR path_name[] = "/test12.txt";
	char cFileName[127];
	FRESULT fr;
	FIL file;
	int res;
	int number = 1;
	int i;
	//int block =0x15b42;

	unsigned int uiTemp = 0;
	SDOnline = SD_CARD_ONLINE;
	os_printf("SD card write test\r\n");

	if (Fatfs_buf != NULL)
	{
		jfree(Fatfs_buf);
	}

	Fatfs_buf = jmalloc(sizeof(FATFS), 1);

	pbuf = jmalloc(SD_TEST_SIZE, 1);
	if (pbuf == NULL)
		return;

	read_buf = jmalloc(SD_TEST_SIZE, 1);
	if (read_buf == NULL)
		return;

	for (i = 0; i < 5 * 512; i++)
	{
		pbuf[i] = 0x55;
	}

	for (i = 5 * 512; i < 6 * 512; i++)
	{
		pbuf[i] = 0x01;
	}

#if 1
	res = f_mount(Fatfs_buf, cFileName, 1);

	if (res == FR_OK)
	{
		os_printf("mount success\r\n");
	}
	else
	{
		os_printf("mount failed: res:%d\r\n", res);
	}
#endif

	sprintf(cFileName, "%d:%s", number, TEST_TXT_FILE_NAME);

	os_printf("\r\n open \"%s\"\r\n", path_name);

	fr = f_open(&file, path_name, FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
	if (fr == FR_OK)
	{
		os_printf(" open file\r\n");

		fr = f_write(&file, pbuf, SD_TEST_SIZE, &uiTemp);
		if (fr != FR_OK)
		{
			os_printf("f_write  failed\r\n");
		}
		else
		{
			os_printf("f_write is ok \r\n");
		}
#if 1
#if 1
		//			f_close(&file);
		//
		//			if(f_open(&file, path_name, FA_OPEN_ALWAYS | FA_READ| FA_WRITE) != 0)
		//			{
		//				os_printf("f_open fail \r\n");
		//			}

		fr = f_lseek(&file, 0);
		if (fr != FR_OK)
		{
			os_printf("f_lseek failed\r\n");
		}

		if (f_read(&file, read_buf, SD_TEST_SIZE, &uiTemp) != 0)
		{
			os_printf("f_read fail \r\n");
		}

#else

		if (0 != sdcard_read_multi_block(read_buf, block, 8))
			os_printf("read error!!!\r\n");

#endif
		if (os_memcmp(read_buf, pbuf, SD_TEST_SIZE) == 0)
		{
			os_printf("wr/rd test success\r\n");
		}
		else
		{
			os_printf("test_write fail\r\n");
			for (i = 0; i < SD_TEST_SIZE; i++)
			{
				if (pbuf[i] != read_buf[i])
					os_printf("write_buf[%d]=0x%x,read_buf[%d]=0x%x\r\n", i, pbuf[i], i, read_buf[i]);
			}
		}
#endif

		f_close(&file);
		os_printf("test over\r\n");
	}
	else
	{
		os_printf("====open failed====\r\n");
	}
	jfree(Fatfs_buf);
	jfree(pbuf);
	jfree(read_buf);
}

void sd_test_write1(void)
{
#define COUNTER 4
#define RW_BUF_SIZE COUNTER *SD_TEST_SIZE
#define TEST_TXT_FILE_NAME "/test1.txt"

	unsigned char *pbuf;
	TCHAR path_name[] = "/test12.txt";
	char cFileName[127];
	FRESULT fr;
	FIL file;
	int res;
	int number = 1;
	int i;

	unsigned int uiTemp = 0;

	/***************          read test          **************/
	unsigned char *read_buf;
	unsigned char *write_buf;
	int count = 0;
	int Block;

	SDOnline = SD_CARD_ONLINE;
	os_printf("SD card write test\r\n");

	if (Fatfs_buf != NULL)
	{
		jfree(Fatfs_buf);
	}

	Fatfs_buf = jmalloc(sizeof(FATFS), 1);

	pbuf = jmalloc(SD_TEST_SIZE, 1);
	if (pbuf == NULL)
		return;

	read_buf = jmalloc(RW_BUF_SIZE, 1);
	if (read_buf == NULL)
		return;

	write_buf = jmalloc(RW_BUF_SIZE, 1);
	if (read_buf == NULL)
		return;

	for (i = 0; i < SD_TEST_SIZE;)
	{
		pbuf[i++] = 0x55;
		pbuf[i++] = 0x56;
		pbuf[i++] = 0x57;
		pbuf[i++] = 0x58;
		pbuf[i++] = 0x59;
		pbuf[i++] = 0x60;
		pbuf[i++] = 0x61;
		pbuf[i++] = 0x62;
	}

	for (i = 0; i < RW_BUF_SIZE;)
	{
		write_buf[i++] = 0x55;
		write_buf[i++] = 0x56;
		write_buf[i++] = 0x57;
		write_buf[i++] = 0x58;
		write_buf[i++] = 0x59;
		write_buf[i++] = 0x60;
		write_buf[i++] = 0x61;
		write_buf[i++] = 0x62;
	}
#if 1
	res = f_mount(Fatfs_buf, cFileName, 1);

	if (res == FR_OK)
	{
		os_printf("mount success\r\n");
	}
	else
	{
		os_printf("mount failed: res:%d\r\n", res);
	}
#endif

	sprintf(cFileName, "%d:%s", number, TEST_TXT_FILE_NAME);

	os_printf("\r\n open \"%s\"\r\n", path_name);

	fr = f_open(&file, path_name, FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
	if (fr == FR_OK)
	{
		os_printf(" open file\r\n");

		for (i = 0; i < 2500; i++)
		{
			fr = f_write(&file, pbuf, SD_TEST_SIZE, &uiTemp);
			if (fr != FR_OK)
			{
				os_printf("f_write  failed\r\n");
			}

			count++;
#if 1
			if (((count % COUNTER) == 0) && (count >= COUNTER))
			{

				if (0 != sdcard_read_multi_block(read_buf, Block, 8 * COUNTER))
					os_printf("read error!!!\r\n");

				if (os_memcmp(read_buf, write_buf, COUNTER * SD_TEST_SIZE) == 0)
				{
					os_printf("compare ok:block:%x\r\n", Block);
				}
				else
				{
					os_printf("compare failed:block:%x\r\n", Block);
					for (i = 0; i < COUNTER * SD_TEST_SIZE; i++)
					{
						if (write_buf[i] != read_buf[i])
							os_printf("write_buf[%d]=0x%x,read_buf[%d]=0x%x\r\n", i, write_buf[i], i, read_buf[i]);
					}
					return;
				}

				Block += 8 * COUNTER;
			}
#endif
		}
		f_close(&file);
		os_printf("test over\r\n");
	}
	else
	{

		os_printf("open fail\r\n");
	}

	//jfree(Fatfs_buf);
}

// EOF
